package org.simpleframework.aop;

import org.simpleframework.aop.annotation.Aspect;
import org.simpleframework.aop.annotation.Order;
import org.simpleframework.aop.aspect.AspectInfo;
import org.simpleframework.aop.aspect.DefaultAspect;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * 实现AOP核心功能实现类
 */
public class AspectWeaver {
    // IOC容器
    private BeanContainer beanContainer;

    public AspectWeaver() {
        this.beanContainer = BeanContainer.getInstance();
    }

    /**
     * 执行AOP核心功能的方法
     */
    public void doAop() {
        // 1) 获取所有的切面类
        Set<Class<?>> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);
        if(ValidationUtil.isEmpty(aspectSet)) return;
        // 2) 把所有的切面类都封装为AspectInfo, 从而得到List<AspectInfo>
        List<AspectInfo> aspectInfoList = packAspectSetToAspectInfoList(aspectSet);
        // 3) 从IOC容器中获得所有的Class,
        Set<Class<?>> classes = beanContainer.getClasses();
        for (Class<?> targetClass : classes) {
            if(targetClass.isAnnotationPresent(Aspect.class)) continue;
            // 4) 对除了@Aspect修饰的以外, 都要作为targetClass进行切面筛选=>粗筛
            List<AspectInfo> roughMatchesList =  roughMatches(targetClass,aspectInfoList);
            // 5) 粗筛后的roughMatchesList, 说明该List都是targetClass的切面, 所以要进行精筛
            //    由于精筛在aspectListExecutor里面, 所以该方法可以直接织入
            weaveIfNecessary(targetClass,roughMatchesList);
        }
    }

    private void weaveIfNecessary(Class<?> targetClass, List<AspectInfo> roughMatchesList) {
        // 通过两个参数生成aspectListExecutor
        AspectListExecutor aspectListExecutor = new AspectListExecutor(targetClass,roughMatchesList);
        // 从而创建动态代理对象
        Object proxyBean = ProxyCreator.createProxy(targetClass, aspectListExecutor);
        // 覆盖IOC容器中的原对象
        beanContainer.addBean(targetClass,proxyBean);
    }

    private List<AspectInfo> roughMatches(Class<?> targetClass, List<AspectInfo> aspectInfoList) {
        List<AspectInfo> roughMatchesList = new ArrayList<>();
        // 对当前targetClass进行粗筛
        for (AspectInfo aspectInfo : aspectInfoList) {
            if (aspectInfo.getPointcutLocator().roughMatches(targetClass)) {
                roughMatchesList.add(aspectInfo);
            }
        }
        return roughMatchesList;
    }

    private List<AspectInfo> packAspectSetToAspectInfoList(Set<Class<?>> aspectSet) {
        List<AspectInfo> aspectInfoList = new ArrayList<>();
        for (Class<?> aspect : aspectSet) {
            if(verifyAspect(aspect)) {
                Order orderTag = aspect.getAnnotation(Order.class);
                Aspect aspectTag = aspect.getAnnotation(Aspect.class);
                // 获得当前Aspect对应的defaultAspect对象
                DefaultAspect defaultAspect = (DefaultAspect) beanContainer.getBean(aspect);
                // 获得当前Aspect对应的pointcutLocator对象
                PointcutLocator pointcutLocator = new PointcutLocator(aspectTag.pointcut());
                // 封装为AspectInfo对象
                AspectInfo aspectInfo = new AspectInfo(orderTag.value(),defaultAspect,pointcutLocator);
                aspectInfoList.add(aspectInfo);
            } else {
                //不遵守规范则直接抛出异常
                throw new RuntimeException("@Aspect and @Order must be added to the Aspect class, and Aspect class must extend from DefaultAspect");
            }
        }
        return aspectInfoList;
    }

    //框架中一定要遵守给Aspect类添加@Aspect和@Order标签的规范，同时，必须继承自DefaultAspect.class
    //此外，@Aspect的属性值不能是它本身
    private boolean verifyAspect(Class<?> aspectClass) {
        return aspectClass.isAnnotationPresent(Aspect.class) &&
                aspectClass.isAnnotationPresent(Order.class) &&
                DefaultAspect.class.isAssignableFrom(aspectClass);
    }
}
